package com.trafficsys.modules.loginAndRegister.service.impl;

import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.trafficsys.modules.entity.*;
import com.trafficsys.modules.licenseplaterecognition.dao.TicketDao;
import com.trafficsys.modules.loginAndRegister.dao.*;
import com.trafficsys.modules.loginAndRegister.pojo.TicketAndRule;
import com.trafficsys.modules.loginAndRegister.service.DriverService;
import com.trafficsys.modules.loginAndRegister.util.MD5Util;
import com.trafficsys.modules.loginAndRegister.util.RedisUtils;
import com.trafficsys.modules.loginAndRegister.util.SmsSend;
import io.lettuce.core.RedisCommandExecutionException;
import org.apache.ibatis.annotations.Param;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.data.redis.support.atomic.RedisAtomicInteger;
import org.springframework.stereotype.Service;

import javax.servlet.http.HttpServletRequest;
import java.net.ConnectException;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.concurrent.TimeUnit;

/**
 * @Author Zhao Bin
 * @Date 2021/9/28 13:10
 * @Version 1.0
 */
@Service
public class DriverServiceImpl implements DriverService {
    @Autowired
    DriverDao driverDao;
    @Autowired
    DriveCardDao driveCardDao;
    @Autowired
    TravelCardDao travelCardDao;
    @Autowired
    TicketDao ticketDao;
    @Autowired
    RuleDao ruleDao;
    @Autowired(required = false)
    private MyNodeDao myNodeDao;//获取权限
    @Autowired
    MD5Util md5Util;
    @Autowired
    private StringRedisTemplate redisTemplate;
    //时间间隔  错误后间隔1分钟后再试
    private static final int TIME_INTERVAL = 1;
    //登录失败重试次数上限制 3次后锁定
    private static final int FAILED_RETRY_TIMES = 3;
    // redis 记录用户登录失败次数key
    private static final String LOGIN_FAILED_COUNT ="LOGIN:FAILED:COUNT:";
    /**
     * 根据key获取计数器
     */
    private RedisAtomicInteger getRedisCounter(String key){
        RedisAtomicInteger counter=
                new RedisAtomicInteger(key,redisTemplate.getConnectionFactory());
        if(counter.get() == FAILED_RETRY_TIMES){
            counter.expire(TIME_INTERVAL, TimeUnit.MINUTES);
        }
        return counter;
    }
    /*********************************************   以下驾驶员功能  *********************************************************
     * 驾驶员注册方法    驾驶员功能
     * @param driver
     * @return
     */
    @Override
    public HashMap<String, Object> register(Driver driver) {
        HashMap<String,Object> map=new HashMap<>();
        int n=0;
        try {
            //密码使用MD5加密加盐
            driver.setPassword(md5Util.getMD5(driver.getPassword()));
            n=driverDao.insert(driver);
            //然后给注册用户添加角色信息
            String roleId="3";//  3：驾驶员  2：警员  1：管理员
            ruleDao.addRoleForDriver(driver.getCardId(),roleId);
        }catch (Exception e){
            e.printStackTrace();
            map.put("info","该身份证或电话号码已被注册");
            return map;
        }
        if(n>=1){//注册成功
            map.put("info","注册成功");
        }else{
            map.put("info","注册失败");
        }
        return map;
    }
    /**
     * 驾驶员密码验证登录    驾驶员功能
     * @param driver
     */
    @Override
    public HashMap<String,Object> driverLogin(Driver driver) {
        HashMap<String,Object> map= new HashMap<>();
        Driver driver1;
        String key;
        //根据登录方式 获取相应的错误登录次数
        try{
            if(driver.getCardId() != null){
                key=LOGIN_FAILED_COUNT + driver.getCardId();
            }else{
                key=LOGIN_FAILED_COUNT + driver.getPhone();
            }
            RedisAtomicInteger counter=getRedisCounter(key);
            //检测错误登录次数 大于上限则锁定一分钟
            if(counter.get() >=FAILED_RETRY_TIMES){
                map.put("info","密码输入错误次数已达上限，请"+TIME_INTERVAL+"分钟后再试！");
                return map;
            }
            //登陆密码 加密处理
            String password=md5Util.getMD5(driver.getPassword());
            if(driver.getCardId() != null){//身份证号码登录
                String cardId=driver.getCardId();
                driver1=driverDao.loginByCardId(cardId,password);
            }else{//电话号码登录
                String phone=driver.getPhone();
                driver1=driverDao.loginByPhone(phone,password);
            }
            //验证登录是否成功
            if(driver1 != null){
                //登录成功后将counter计数器清零
                redisTemplate.delete(key);
                map.put("info","登录成功");
                //返回登录对象
                map.put("driver",driver1);
            }else{
                //登录失败次数加一
                counter.getAndIncrement();
                map.put("info","您已经输入密码错误"+counter+"次！！");
            }
        } catch (RedisCommandExecutionException e){
            e.printStackTrace();
            map.put("info","redis数据库中间件出错了");
        }catch (Exception e){
            e.printStackTrace();
            map.put("info","登录功能出错");
        }
        return map;
    }
    /**
     * 根据cardId查询个人信息    驾驶员功能
     */
    @Override
    public HashMap<String, Object> getDriverByCardId(String cardId) {
        HashMap<String,Object> map=new HashMap<>();
        Driver driver=driverDao.getDriverByCardId(cardId);
        if(driver !=null){
            List<DriveCard> driveCards=driveCardDao.getDriveCardByCardId(cardId);
            List<TravelCard> travelCards=travelCardDao.getTravelCardByCardId(cardId);
            driver.setDriveCardList(driveCards);
            driver.setTravelCardList(travelCards);
            map.put("driver",driver);
            return map;
        }else{
            map.put("info","查无此用户");
            return map;
        }
    }

    /**
     * 驾驶员查询自己驾驶证    驾驶员功能
     * 查询出来 放入redis缓存中
     */
    @Override
    public IPage<DriveCard> getDriveCardByCardId(Page<DriveCard> page, String cardId) {
        return driveCardDao.getDriveCardByCardId(page,cardId);
    }
    /**
     * 驾驶员查询自己行驶证    驾驶员功能
     */
    @Override
    public IPage<TravelCard> getTravelCardByCardId(Page<TravelCard> page, String cardId){
        return travelCardDao.getTravelCardByCardId(page,cardId);
    }

    /**
     * 根据phone查询到驾驶员信息
     */
    @Override
    public HashMap<String, Object> getDriverByPhone(String phone) {
        HashMap<String,Object> map=new HashMap<>();
        Driver driver=driverDao.getDriverByPhone(phone);
        map.put("driver",driver);
        return map;
    }
    /**
     *
     */
    @Override
    public HashMap<String, Object> updateDriver(Driver driver) {
        HashMap<String,Object> map=new HashMap<>();
        //1、查询更改的cardId与phone是否对应 是则更新数据
        //1.1 根据cardId查询出对应用户  没有查到 就返回查无此用户  查到就对比phone
        try{
            Driver driver1=driverDao.getDriverByCardId(driver.getCardId());
            if(driver1.getCardId()!=null && driver1.getPhone()!=null){
                if(driver1.getPhone().equals(driver.getPhone())){
                    //把原本的用户id赋值给修改用户 然后更新原用户
                    driver.setId(driver1.getId());
                    //将新密码加密后存储数据库
                    driver.setPassword(md5Util.getMD5(driver.getPassword()));
                    driverDao.updateById(driver);
                    map.put("driver",driver);
                    map.put("info","修改成功");
                    return map;
                }else{
                    map.put("info","绑定手机号码错误");
                    return map;
                }
            }else{
                map.put("info","查无此用户");
                return map;
            }
        }catch (NullPointerException e){
            e.printStackTrace();
            map.put("info","该用户尚未注册");
            return map;
        } catch (Exception e){
            e.printStackTrace();
            map.put("info","修改密码失败");
            return map;
        }
    }
    /**
     * 获取权限
     */
    @Override
    public HashMap<String, Object> driverSelectPower(String cardId) {
        HashMap<String,Object> map=new HashMap<>();
        List<MyNode> list=myNodeDao.driverSelectPower(cardId);
        List<MyNode> powerList=new ArrayList<>();
        if (list!=null){
            //构建权限菜单的数据结构
            for (MyNode one:list){
                if (one.getParentId()==0){
                    //ParentId为0 则有子菜单  非零则 没有子菜单
                    MyNode mn=new MyNode();
                    mn.setUrl(one.getUrl());
                    mn.setIndex(one.getIndex());
                    mn.setName(one.getName());
                    System.out.println(one.getName().toString());
                    //创建一个集合
                    List<MyNode> listChildren=new ArrayList<>();
                    //遍历 父节点等于上面子节点的Node 则为上面的菜单的子菜单
                    for(MyNode two:list){
                        if (two.getParentId()==one.getNodeId()){
                            listChildren.add(two);
                            System.out.println(two.getName().toString());
                        }
                    }
                    //将父菜单的子菜单 装入父菜单的子菜单集合list
                    mn.setChildren(listChildren);
                    powerList.add(mn);
                }
            }
        }
        map.put("powerList",powerList);
        return map;
    }
    /**
     * 退出系统
     */
    @Override
    public HashMap<String, Object> driverLogout(Driver driver) {
        HashMap<String,Object> map= new HashMap<>();
        //将redis缓存中的该用户数据清除、
        String key;
        if(driver.getCardId() != null){
            key=LOGIN_FAILED_COUNT + driver.getCardId();
            redisTemplate.delete(key);
        }else if (driver.getPhone() != null){
            key=LOGIN_FAILED_COUNT + driver.getPhone();
            redisTemplate.delete(key);
        }
        map.put("info","成功清除缓存数据");
        return map;
    }
    /**
     * 查询用户 已处理罚单信息
     */
    @Override
    public IPage<TicketAndRule> getSolvedTicketAndRuleByCardId(Page<TicketAndRule> page, String cardId) {
        return driverDao.getSolvedTicketAndRuleByCardId(page,cardId);

    }
    /**
     * 查查询用户 未处理罚单信息
     */
    @Override
    public IPage<TicketAndRule> getNoSolveTicketAndRuleByCardId(Page<TicketAndRule> page, String cardId) {
        return driverDao.getNoSolveTicketAndRuleByCardId(page,cardId);
    }

    /**
     * 处理罚单
     */
    @Override
    public HashMap<String, Object> solveTicket(String id, String cardId,String cutScore) {
        HashMap<String,Object> map=new HashMap<>();
        try{
            //1、扣除驾驶证的分数
            //1.1获取驾驶证
            List<DriveCard> driveCardList=driveCardDao.getDriveCardByCardId(cardId);
            if(driveCardList.get(0).getScore()<=0){
                driveCardList.get(0).setState("吊销");
                map.put("info","驾驶证已被吊销,罚单处理失败，请重新考试获取驾驶证。");
            }else{
                driveCardList.get(0).setScore(driveCardList.get(0).getScore()-(Integer.parseInt(cutScore)));
                if(driveCardList.get(0).getScore()<=0){
                    driveCardList.get(0).setState("吊销");
                }
                driveCardDao.updateById(driveCardList.get(0));
                //2、改变罚单状态 并赋上现在的时间为处理时间
                //2.1获取当前时间
                Ticket ticket=ticketDao.getTicketById(id);
                ticket.setState("已处理");
                ticket.setUpdateTime(new Date());
                //更新罚单
                ticketDao.updateTicketById(ticket);
                map.put("info","处理罚单成功");
            }
        }catch (Exception e){
            e.printStackTrace();
            map.put("info","处理罚单失败");
        }
        //3、返回处理信息
        return map;
    }
    /**
     * 分页查询所有驾驶证
     */
    @Override
    public IPage<DriveCard> getAllDriveCard(IPage<DriveCard> page) {
        return driverDao.getAllDriveCard(page);
    }
    /**
     * 分页查询所有驾驶证
     */
    @Override
    public IPage<TravelCard> getAllTravelCard(IPage<TravelCard> page) {
        return driverDao.getAllTravelCard(page);
    }
}
